package net.m2technologies.open_arm.utilities;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import java.util.StringTokenizer;

/**
 * Copyright 2005 Mark Masterson<br> <br> Licensed under the Apache License, Version 2.0 (the "License");<br> you may
 * not use this file except in compliance with the License.<br> You may obtain a copy of the License at<br> <br>
 * http://www.apache.org/licenses/LICENSE-2.0<br> <br> Unless required by applicable law or agreed to in writing,
 * software<br> distributed under the License is distributed on an "AS IS" BASIS,<br> WITHOUT WARRANTIES OR CONDITIONS
 * OF ANY KIND, either express or implied.<br> See the License for the specific language governing permissions and<br>
 * limitations under the License.<br>
 * <p/>
 * <p>Description: </p>
 *
 * @author Mark Masterson
 * @version 0.010
 */
public class Strings {

    private static final char BLANK_SPACE = ' ';

    /**
     * Searches the string passed as first parameter for all occurences of the string passed as the second one.
     *
     * @param stringToTest
     * @param searchForValue
     *
     * @return number of occurences
     */
    public static int countForAllOccurencesOf(final String stringToTest, final String searchForValue) {
        if (null == stringToTest || null == searchForValue) {
            throw new IllegalArgumentException("None of the parameter-strings must be null!");
        }
        int count = 0;
        final int searchHit = stringToTest.indexOf(searchForValue);

        if (0 <= searchHit) {
            count++;
            count += countForAllOccurencesOf(stringToTest.substring(searchHit + searchForValue.length()),
                                             searchForValue);
        }
        return count;
    }

    /**
     * Searches the String passed as first parameter for the String passed as second parameter, and replaces that
     * String, if found, with the String passed as third parameter.  Will not replace two occurences of the
     * "stringToReplace" parameter that are found directly next to each other.
     *
     * @param stringToTest
     * @param stringToReplace
     * @param replacementValue
     *
     * @return the transformed String value
     */
    public static String replaceAllOccurencesOf(final String stringToTest,
                                                final String stringToReplace,
                                                final String replacementValue) {
        String result = stringToTest;
        if (null == result
            || null == stringToReplace
            || null == replacementValue) {
            throw new IllegalArgumentException("None of the parameters to this method may be null!");
        }
        if (stringToReplace.equals(replacementValue)) return result;
        final StringBuffer buf = new StringBuffer(result.length() + replacementValue.length() * 4);
        final int searchHit = result.indexOf(stringToReplace);
        if (0 <= searchHit) {
            final int doubleSearchHit = result.indexOf(stringToReplace, searchHit + stringToReplace.length());
            if (0 > doubleSearchHit || 1 < doubleSearchHit - searchHit) {
                buf.append(result.substring(0, searchHit))
                        .append(replacementValue)
                        .append(replaceAllOccurencesOf(result.substring(searchHit + stringToReplace.length(),
                                                                        result.length()),
                                                       stringToReplace,
                                                       replacementValue));
            } else if (1 >= doubleSearchHit - searchHit) {
                buf.append(result.substring(0, searchHit))
                        .append(replacementValue)
                        .append(replaceAllOccurencesOf(result.
                                substring(doubleSearchHit + stringToReplace.length(),
                                          result.length()),
                                                       stringToReplace,
                                                       replacementValue));
            }
            result = buf.toString();
        }
        return result;
    }

    /**
     * Collapses a String{} into a String.
     *
     * @param stringArrayValue
     *
     * @return String
     */
    public static final String convertStringArrayToString(final String[] stringArrayValue) {
        final StringBuffer result = new StringBuffer(stringArrayValue.length);
        for (int i = 0; i < stringArrayValue.length; i++) {
            result.append(stringArrayValue[i]);
            result.append(BLANK_SPACE);
        }
        return result.toString().trim();
    }

    /**
     * Parses a String, using a blank as default delimiter, and converts it to a String{}, where each element of the
     * array is one of the tokens found in the delimited String.
     *
     * @param stringValue -- the String to parse
     *
     * @return an array of Strings, where each element is a token found in the delimited String
     */
    public static final String[] convertStringToStringArray(final String stringValue) {
        return convertStringToStringArray(stringValue, " ");
    }

    /**
     * Parses a String, using the give delimiter, and converts it to a String{}, where each element of the array is one
     * of the tokens found in the delimited String.
     *
     * @param stringValue -- the String to parse
     * @param delimiter   -- delimiter to use in parsing the String
     *
     * @return an array of Strings, where each element is a token found in the delimited String
     */
    public static final String[] convertStringToStringArray(final String stringValue, final String delimiter) {
        final String[] result;
        final Collection list = parseStringToCollection(stringValue, delimiter);
        result = new String[list.size()];
        int i = 0;
        final Iterator listIt = list.iterator();
        while (listIt.hasNext()) {
            result[i] = (String) listIt.next();
            ++i;
        }
        return result;
    }

    /**
     * Parses a String, using the given delimiter, and adds each token thus found to a Collection.
     *
     * @param stringValue -- the String to parse
     * @param delimiter   -- delimiter to use in parsing the Stringue
     * @param delimiter
     *
     * @return -- a Collection, whose elements are the tokens found in the delimited String.
     */
    public static final Collection parseStringToCollection(final String stringValue, final String delimiter) {
        if (null != stringValue) {
            final Collection list = new ArrayList();
            final StringTokenizer tokenizer = new StringTokenizer(stringValue, delimiter);
            while (tokenizer.hasMoreTokens()) {
                final String einToken = tokenizer.nextToken();
                if (null != einToken) {
                    list.add(einToken);
                }
            }
            return list;
        }
        return null;
    }

    /**
     * Determines wether the passed string is of numeric value.
     *
     * @param stringToTest
     *
     * @return true (string is of numeric value) or false (string contains at least one non-numeric character)
     */
    public static boolean isNumeric(final String stringToTest) {
        boolean result = true;
        try {
            Long.parseLong(stringToTest);
        } catch (NumberFormatException e) {
            result = false;
        }
        return result;
    }

    /**
     * Checks the String passed as parameter, and returns a programmatic null if it is an empty string.  Simply returns
     * the paramater unchanged if not an empty string.
     */
    public String returnNullIfEmptyString(final String stringToCheck) {
        if ("".equals(stringToCheck)) return null;
        return stringToCheck;
    }

    /**
     * Checks if the parameter passed is a null, and if yes returns an empty string.
     */
    public String returnEmptyStringIfNull(final String stringToCheck) {
        if (null == stringToCheck) return "";
        return stringToCheck;
    }
}
